package com.hsgene.gateway.support.filter;

import com.hsgene.authority.exception.AuthorityErrorCode;
import com.hsgene.common.ClientType;
import com.hsgene.common.util.result.ApiResult;
import com.hsgene.common.util.web.session.UserInfo;
import com.hsgene.common.util.web.session.UserInfoExtra;
import com.hsgene.gateway.service.api.LoginCheckService;
import com.hsgene.gateway.service.api.SecurityService;
import com.hsgene.gateway.support.ClientRequestFilter;
import com.hsgene.user.exception.UserErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.List;
import java.util.stream.Stream;

/**
 * 运营后台请求过滤器
 *
 * @author wangbing
 * @version 1.0, 2018/11/9
 */
@Component
public class ConsoleClientRequestFilter implements ClientRequestFilter {

    private final static Logger LOGGER = LoggerFactory.getLogger(ConsoleClientRequestFilter.class);

    @Resource
    private RedisTemplate<Serializable, Serializable> redisTemplate;

    @Resource
    private LoginCheckService loginCheckService;

    @Resource
    private SecurityService securityService;

    @Value("${redis.prefix.authority.permission.department}")
    private String redisPermissionDepartmentKey;

    @Value("#{'${special.validation.permission.urls}'.split(',')}")
    private String[] specialValidationPermissionUrls;

    @Override
    public ClientType filterType() {
        return ClientType.CONSOLE;
    }

    @Override
    public int filterOrder() {
        return 5;
    }

    @Override
    public boolean shouldFilter(HttpServletRequest request) {
        // 此处为运营后台用户权限校验
        return ClientType.CONSOLE.equals(ClientType.getEnum(Integer.valueOf(request.getParameter("platform"))));
    }

    @Override
    public ApiResult run(HttpServletRequest request) {
        String sessionId = request.getHeader("session_id");
        String accessToken = request.getHeader("access_token");
        if (StringUtils.isEmpty(sessionId) || StringUtils.isEmpty(accessToken)) {
            String currentRequestApi = request.getMethod() + " " + request.getRequestURI();
            if (Stream.of(specialValidationPermissionUrls).anyMatch(currentRequestApi::matches)) {
                String sign = request.getParameter("sign");
                if (!StringUtils.isEmpty(sign)) {
                    try {
                        sign = URLDecoder.decode(sign, "utf-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                        return ApiResult.fail(UserErrorCode.USER_NOT_LOGIN);
                    }
                    ApiResult<String> decryptResult = securityService.rsaDecrypt(sign);
                    if (!decryptResult.isSucc()) {
                        return ApiResult.fail(decryptResult.getError());
                    }
                    String[] data = decryptResult.getData().split("&");
                    if (data.length >= 2) {
                        sessionId = data[0];
                        accessToken = data[1];
                    }
                }
            }
            if (StringUtils.isEmpty(sessionId) || StringUtils.isEmpty(accessToken)) {
                return ApiResult.fail(UserErrorCode.USER_NOT_LOGIN);
            }
        }
        ApiResult<UserInfo> loginCheckResult = loginCheckService.checkLoginStatus(sessionId, accessToken);

        if (!loginCheckResult.isSucc()) {
            LOGGER.error("用户登录检测失败：" + loginCheckResult.getDesc());
            return loginCheckResult;
        }
        // 用户权限判断
        UserInfo user = loginCheckResult.getData();
        UserInfoExtra extra = user.getExtra();
        boolean access = true;
        // 超级管理员拥有全部权限，不做后续判断
        if (extra != null && Boolean.TRUE.equals(extra.getSystemSuper())) {
            return ApiResult.succ();
        }
        if (extra == null || extra.getDepartmentId() == null) {
            access = false;
        }
        if (!access) {
            return ApiResult.fail(AuthorityErrorCode.USER_PERMISSION_NOT_ENOUGH);
        }
        String redisKey = redisPermissionDepartmentKey + extra.getDepartmentId();
        String currentRequestApi = request.getMethod() + " " + request.getRequestURI();
        List<Serializable> data = redisTemplate.opsForList().range(redisKey, 0, -1);
        if (CollectionUtils.isEmpty(data)) {
            return ApiResult.fail(AuthorityErrorCode.USER_PERMISSION_NOT_ENOUGH);
        }
        access = data.stream().map(e -> (String) e).anyMatch(currentRequestApi::matches);
        if (!access) {
            return ApiResult.fail(AuthorityErrorCode.USER_PERMISSION_NOT_ENOUGH);
        }

        return ApiResult.succ();
    }
}
